/*
具体调用方法
// app.js
const Event = require('./event')
App({
    event: new Event(),
    ...
})
//订阅.js
var app = getApp()
Page({
    onLoad: function(){
        app.event.on('afterPaySuccess',this.afterPaySuccess.bind(this))
    },
    afterPaySuccess: function(orderId) {
        ...
    },
    ...
})
//监听.js
var app = getApp()
Page({
    raisePayment: function() {
        ...
        app.event.emit('afterPaySuccess', orderId)
    },
    ...
})
//所有 Page 的 onUnload 生命周期，必须注销掉之前订阅的事件。
Page({
    onUnload: function(){
        // remove all
        app.event.off()
        // remove all callbacks
        app.event.off('afterPaySuccess')
        // remove specific callbacks
        app.event.off('afterPaySuccess', this.afterPaySuccess)
    },
    ...
})
*/
class Event{
    on (event, fn, ctx) {
        if (typeof fn != "function") {
            console.error('fn must be a function')
            return
        }

        this._stores = this._stores || {}

        ;(this._stores[event] = this._stores[event] || []).push({cb: fn, ctx: ctx})
    }

    once (event, fn, ctx) {
        let that = this;
        let newfn = function () {
            let args = Array.prototype.slice.call(arguments);
            fn.apply(this, args);
            that.off(event, newfn);
        }
        this.on(event, newfn, ctx);
    }

    emit (event) {
        this._stores = this._stores || {}
        var store = this._stores[event], args
        if (store) {
            store = store.slice(0)
            args = [].slice.call(arguments, 1)
            for (var i = 0, len = store.length; i < len; i++) {
                store[i].cb.apply(store[i].ctx, args)
            }
        }
    }

    off (event, fn) {
        this._stores = this._stores || {}
        // all
        if (!arguments.length) {
            this._stores = {}
            return
        }
        // specific event
        var store = this._stores[event]
        if (!store) return
        // remove all handlers
        if (arguments.length === 1) {
            delete this._stores[event]
            return
        }
        // remove specific handler
        var cb
        for (var i = 0, len = store.length; i < len; i++) {
            cb = store[i].cb
            if (cb === fn) {
                store.splice(i, 1)
                break
            }
        }
        return
    }
}

module.exports = Event;